package cichlid.seprphase3.GUIInterface;

import cichlid.seprphase3.Simulator.Simulator;
import cichlid.seprphase3.Utilities.Energy;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.*;

/**
 * This GameState defines the current state of the game.
 */
enum GameState {
    NotStarted, Running, GameOver, TwoPlayer
}

/**
 * The GUIWindow class extends JFrame and provides methods for dealing with the current
 * interface. It implements ActionListener so it can work with Swing Timers for scheduling
 * updating at a specified interval.
 */
public class GUIWindow extends JFrame implements ActionListener, KeyListener {

    // This is the current window which is being displayed.
    JPanel currentWindow;
    
    // This is the simulator which the plant uses.
    Simulator simulator;
    
    // This is the state which the game is currently in.
    GameState state = GameState.NotStarted;
    
    
    // This is the GameOverInterface which is displayed when the game is over.
    GameOverInterface gameover;
    // The end game explosion animation must be preloaded due to its size, so it is stored here.
    Animation explosion;
    
    int defaultGraphicsPlantUpdateRatio = 10;
    int untilPlantUpdate = defaultGraphicsPlantUpdateRatio;
    
    //Used to stop player 2 cheating by holding down the spambar
    boolean spaceBarReleased = true;
    
    //Boolean used to check whether the first 2P game has been played.
    boolean swapped = false;
    
    //Score for two player mode
    Energy player1score;
    String player1name;
    Energy player2score;
    String player2name;
    
    /**
     * This creates a GUIWindow with a number of parameters.
     * @param title         The title to give the window.
     * @param width         The width of the window.
     * @param height        The height of the window.
     */
    public GUIWindow(String title, int width, int height) {
        
        super(title);
       
        // Allow the window to exit when the close button is pressed.
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        // Set the resolution of the window.
        setSize(width, height);

        // If the location is relative to nothing, the window always starts in the middle of the screen.
        setLocationRelativeTo(null);
        // Do not allow the user to resize the window.
        setResizable(false);
        setVisible(true);
        
        // Preload the Explosion Animation due to its size and store it here to be passed into
        // GameOverInterface.
        explosion = new Animation("animations/explosion", false);
        this.addKeyListener(this);
        
    }

    /**
     * This is called to run the game when it first starts.
     */
    public void run() {
        // Show the menu screen.
        showMenu();

        // Setup the timer which is used to update the plant.
        // This makes actionPerformed() be called every 60ms.
        Timer timer = new Timer(60, this);
        timer.start();
        
    }

    /**
     * Called every 60ms by the Swing Timer.
     * @param event 
     */
    @Override
    public void actionPerformed(ActionEvent event) {
        // Decide which action to take based on what state the interface is currently in.
        switch (state) {
            // If the game is running, step the simulator and update.
            case Running: case TwoPlayer:
                // Simulator.step returns false if the game is over, in which case the else clause is ran:
                if(untilPlantUpdate <= 0)
                {
                    if (simulator.step()) 
                    {
                        update();
                    } else
                        // if block for 2p intermission
                        if(!swapped && state == GameState.TwoPlayer) 
                        {   
                            swapped = true; 
                            player1score = simulator.energyGenerated();
                            player1name = simulator.getUsername();
                            state = GameState.GameOver;
                            gameover = new GameOverInterface(explosion, player1score, player1name, true);
                            setWindow(gameover);
                          
                        }
                        //if block for 1player.
                        else if(state == GameState.Running){
                              // Set the game state to GameOver (so the plant stops updating).
                              // And set the interface to the GameOverInterface.
                              // Some values to display are passed in from the simulator.
                              state = GameState.GameOver;
                              gameover = new GameOverInterface(explosion, simulator.energyGenerated(), simulator.getUsername());
                              setWindow(gameover);
                           }
                        //if block for end of 2player
                        else if(swapped && state == GameState.TwoPlayer){
                            player2score = simulator.energyGenerated();
                            player2name = simulator.getUsername();
                            state = GameState.GameOver;
                            gameover = new GameOverInterface(explosion, player1score, player1name, player2score, player2name);
                            setWindow(gameover);
                        }
                    
                    untilPlantUpdate = defaultGraphicsPlantUpdateRatio;
                }
                else
                    untilPlantUpdate--;
                update();
                break;
            // If the game is over, just continue repainting to show the GameOverInterface.
            case GameOver:
                update();
                // gameover.block returns false when the button is pressed to play another game. At this point,
                // the code to return to the menu interface is ran.
                //if block for the end of 1p or 2p mode, will return to main menu.
                if(!gameover.twoPlayer && !gameover.block    //1p mode
                   || gameover.twoPlayer && !gameover.afterFirst && !gameover.block) { //end of 2p mode
                        state = GameState.NotStarted;
                        resetScoresAndNames();
                        showMenu();
                }
                //if block for 2player intermission. Will start the 2nd round.
                else if(gameover.twoPlayer && gameover.afterFirst && !gameover.block){
                    state = GameState.TwoPlayer;
                    simulator=new Simulator();
                    simulator.setUsername(player2name);
                    setWindow(new PlantInterface(this, simulator, simulator, simulator));
                }
                break;
            // If the game is in any other screen, just continue as normal.
            default:
                update();
                break;
        }
    }

    /**
     * Sets the active interface on the jFrame (all interfaces are jPanels).
     *
     * @param _window       The interface to display.
     */
    public void setWindow(JPanel _window) {
        /**
         * The content pane represents the area of the window where content is shown - all of the window except the
         * title bar. Setting the content panel to a jPanel causes the jPanel to draw to the window.
         */
        currentWindow = _window;
        setContentPane(_window);
        //currentWindow.requestFocusInWindow();//!
    }

    /**
     * Update the window. Revalidate causes the jPanel to revalidate, while redraw redraws the jPanel's content to the
     * screen.
     */
    public void update() {
        revalidate();
        repaint();
    }

    /**
     * Run game starts a new game. It is called by Load, and takes the loaded simulator, creating the new game with
     * it.
     * @param sim 
     */
    public void runGame(Simulator sim) {
        simulator = sim;
        setWindow(new PlantInterface(this, simulator, simulator, simulator));
        state = GameState.Running;
    }
    
    public void showMenu() {
        simulator = new Simulator();
        setWindow(new MenuInterface(this, simulator));
    }
    
    public Enum getGameState(){
        return state;
    }
    
    public void resetScoresAndNames(){
        player1name = null;
        player2name = null;
        player1score = null;
        player2score = null;
    }

    @Override
    public void keyPressed(KeyEvent e)
    {
       if(e.getKeyCode()==32)
           if(spaceBarReleased){
                handleSpaceBarPressed();
                spaceBarReleased = false;
           }
       if(e.getKeyCode()==10)
           handleEnterPressed();
        
    }
    //two player only
    private void handleSpaceBarPressed()
    {
        if(state == GameState.TwoPlayer)
        {
            PlantInterface pi = (PlantInterface) currentWindow;
            pi.getSpamBar().increment(1.6);
        } 
    }
    
    // two player only
    private void handleEnterPressed()
    {
        if(state == GameState.TwoPlayer)
        {
            PlantInterface pi = (PlantInterface) currentWindow;
            double value = pi.getSpamBar().getSpamBarValue();
            if(value>=100)
                simulator.failReactor();
            else if(value>=90)
                simulator.failCondenser();
            else if(value>=80)
                simulator.failSoftware();
            else if(value>=60)
                simulator.failTurbine();
            else if(value>=40)
                simulator.failMainPump();
            else if(value>=20)
                simulator.failCoolingPump();   
            
            pi.getSpamBar().setSpamBarValue(0);
        } 
    }

    @Override
    public void keyReleased(KeyEvent e)
    {
        if(e.getKeyCode()==32)
            spaceBarReleased = true;
        
    }

    @Override
    public void keyTyped(KeyEvent arg0)
    {
        // TODO Auto-generated method stub
        
    }
    
}
